﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Compilex.BaseLibrary
{
    /// <summary>
    /// Uma lista simples, que permite adicionar elementos
    /// arbitrariamente.
    /// </summary>
    /// <typeparam name="T">O tipo do objeto armazenado</typeparam>
    [Serializable]
    public class SimpleList<T>
    {
        private int defaultCapacity = 4;
        private T[] items;
        private int actualSize;

        /// <summary>
        /// Obtém o número de elementos da lista
        /// </summary>
        public int Count
        {
            get { return actualSize; }
        }

        /// <summary>
        /// Constroi uma SimpleList vazia
        /// </summary>
        public SimpleList()
        {
            items = new T[defaultCapacity];
        }

        /// <summary>
        /// Constrói uma lista a partir de um vetor existente.
        /// </summary>
        /// <param name="collection"></param>
        public SimpleList(T[] collection)
        {
            items = new T[collection.Length];
            foreach (T obj in collection)
            {
                this.Add(obj);
            }
        }
        /// <summary>
        /// Constrói uma lista a partir de uma lista existente.
        /// </summary>
        /// <param name="collection"></param>
        public SimpleList(SimpleList<T> collection)
            : this(collection.ToArray())
        {
        }


        /// <summary>
        /// Adiciona um elemento à lista
        /// </summary>
        /// <param name="item"></param>
        public void Add(T item)
        {
            this.EnsureCapacity(this.actualSize + 1);
            this.items[this.actualSize++] = item;
        }

        private void EnsureCapacity(int min)
        {
            if (this.items.Length < min)
            {
                int num = (this.items.Length == 0) ? defaultCapacity : (this.items.Length * 2);
                if (num < min)
                {
                    num = min;
                }
                this.IncreaseCapacity(num);
            }

        }

        /// <summary>
        /// Aumenta a capacidade da lista.
        /// </summary>
        /// <param name="num"></param>
        public void IncreaseCapacity(int num)
        {
            if (num < this.actualSize)
            {
                throw new ArgumentOutOfRangeException();
            }
            if (num > 0)
            {
                T[] destinationArray = new T[num];
                if (this.actualSize > 0)
                {
                    ArrayUtils.Copy(this.items, destinationArray);
                }
                this.items = destinationArray;
            }
        }

        /// <summary>
        /// Obtém o objeto armazenado em um índice da lista através de um
        /// indexer (pode ser acessado por simpleList[indice]).
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public T this[int index]
        {
            get
            {
                if (index >= this.actualSize)
                {
                    throw new ArgumentOutOfRangeException();
                }
                return this.items[index];
            }
            set
            {
                if (index >= this.actualSize)
                {
                    throw new ArgumentOutOfRangeException();
                }
                this.items[index] = value;
            }
        }

        public void AddRange(SimpleList<T> list)
        {
            for (int i = 0; i < list.Count; i++)
            {
                this.Add(list[i]);
            }
        }

        public T[] ToArray()
        {
            T[] array = new T[this.Count];
            for (int i = 0; i < this.Count; i++)
            {
                array[i] = this[i];
            }
            return array;
        }

        public void AddRange(IEnumerable<T> list)
        {
            foreach (T element in list)
            {
                this.Add(element);
            }
        }

        public bool Contains(T element)
        {
            for (int i = 0; i < this.Count; i++)
            {
                if(this[i].Equals(element))
                    return true;
            }
            return false;
        }
    }
}
